package core.proto;

import core.util.logging.constants.Action;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.io.FilenameUtils;

import core.util.logging.UserLogWriter;
import core.util.logging.constants.Location;


public class ClosableTabbedPane extends JTabbedPane{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private TabCloseXButton closeUI;

	private int previousTabCount;

	public static final int TAB_WIDTH = 80; 
	public static final int TAB_HEIGHT = 15;
	
	public ClosableTabbedPane(){
		closeUI = new TabCloseXButton(this);
		previousTabCount = 0;
		this.addTabSwitchListener();
	}

	public void paint(Graphics g){
		super.paint(g);
		closeUI.paint(g);
	}

	
	
	private void addTabSwitchListener(){
		final ClosableTabbedPane pane = this; 
		ChangeListener changeListener = new ChangeListener() {

			public void stateChanged(ChangeEvent changeEvent) {
				// We switched tabs only if previous tab count is same 
				if (previousTabCount == pane.getTabCount()){
					JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent.getSource();
					int index = sourceTabbedPane.getSelectedIndex();
					UserLogWriter.log2("Switched to " + sourceTabbedPane.getTitleAt(index), Location.Documents, Action.SWITCHDOC);
				}
				pane.previousTabCount = pane.getTabCount();
			}
		};
		this.addChangeListener(changeListener);
	}

	public void addTab(String absolutePath, Component component) {
		super.addTab("", component);

		JLabel tabComponent = new JLabel(absolutePath);
		tabComponent.setOpaque(false);
		
		JPanel panel = new JPanel();
		panel.setOpaque(false);
		panel.setLayout(new BorderLayout());
		panel.add(tabComponent, BorderLayout.WEST);
		// We control the dimension of the tab by setting the preferred size. 
		panel.add(closeUI, BorderLayout.EAST);
		panel.setPreferredSize(new Dimension(TAB_WIDTH, TAB_HEIGHT));
		this.setTabComponentAt(this.getTabCount()-1, panel);
	}

	private class TabCloseXButton extends JComponent implements MouseListener, MouseMotionListener {
		private static final long serialVersionUID = 1L;
		private ClosableTabbedPane  tabbedPane;
		private int closeX = 0 ,closeY = 0, meX = 0, meY = 0;
		private int selectedTab;
		private final int  width = 8, height = 8;
		private Rectangle rectangle = new Rectangle(0,0,width, height);
		public TabCloseXButton(ClosableTabbedPane pane) {

			tabbedPane = pane;
			tabbedPane.addMouseMotionListener(this);
			tabbedPane.addMouseListener(this);
		}
		public void mouseEntered(MouseEvent me) {}
		public void mouseExited(MouseEvent me) {}
		public void mousePressed(MouseEvent me) {}


		public void mouseClicked(MouseEvent me) {
			//UserLogWriter.log(tabbedPane.getTabCount() == 0 ? "" : FilenameUtils.getBaseName(AllComponents.getCurrentPath()), Location.Documents, Action.getClicks(me.getClickCount()));
		}
		public void mouseDragged(MouseEvent me) {}



		public void mouseReleased(MouseEvent me) {
			if(closeUnderMouse(me.getX(), me.getY())){
				int index = AllComponents.getMultipleDocs().getSelectedIndex();
				if (index > -1){           
					// call FileTree to collapse the node by absolutePath - sue
					String absolutePath = AllComponents.openTabs.get(index);
					// remove the selectedTab. 
					// this is hackish because openTabs.remove MUST be updated 
					// before updating the tabbedPane, or the changedEvent 
					// handler in AllComponets doesn't work correctly
					// as it depends on tabbedPane and openTabs having 
					// corresponding elements. 
					AllComponents.openTabs.remove( index );
					tabbedPane.removeTabAt(index);
					AllComponents.getFileTree().treeNodeClosedByPath(absolutePath);
					AllComponents.getFileTree().tree.clearSelection();
					UserLogWriter.log2(FilenameUtils.getBaseName(absolutePath), Location.Documents, Action.CLOSEDOC);
				}
				selectedTab = tabbedPane.getSelectedIndex();
			}
		}

		public void mouseMoved(MouseEvent me) { 
			meX = me.getX();
			meY = me.getY();            
			if(mouseOverTab(meX, meY)){
				controlCursor();
				tabbedPane.repaint();
			}
		}

		private void controlCursor() {
			if(tabbedPane.getTabCount()>0)
				if(closeUnderMouse(meX, meY)){
					tabbedPane.setCursor(new Cursor(Cursor.HAND_CURSOR));   
					if(selectedTab > -1)
						tabbedPane.setToolTipTextAt(selectedTab, "Close " +tabbedPane.getTitleAt(selectedTab));
				}
				else{
					tabbedPane.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
					if(selectedTab > -1)
						tabbedPane.setToolTipTextAt(selectedTab,"");
				}   
		}

		private boolean closeUnderMouse(int x, int y) {     
			rectangle.x = closeX;
			rectangle.y = closeY;
			return rectangle.contains(x,y);
		}

		public void paint(Graphics g) {

			int tabCount = tabbedPane.getTabCount();
			for(int j = 0; j < tabCount; j++)
			{
				if(tabbedPane.getComponent(j).isShowing()){         
					int x = tabbedPane.getBoundsAt(j).x + tabbedPane.getBoundsAt(j).width -width-5;
					int y = tabbedPane.getBoundsAt(j).y +5; 
					drawClose(g,x,y);
					break;
				}
			}
			if(mouseOverTab(meX, meY)){
				drawClose(g,closeX,closeY);
			}
		}

		private void drawClose(Graphics g, int x, int y) {
			if(tabbedPane != null && tabbedPane.getTabCount() > 0){
				Graphics2D g2 = (Graphics2D)g;              
				drawColored(g2, isUnderMouse(x,y)? Color.RED : Color.WHITE, x, y);
			}
		}

		private void drawColored(Graphics2D g2, Color color, int x, int y) {
			g2.setStroke(new BasicStroke(5,BasicStroke.JOIN_ROUND,BasicStroke.CAP_ROUND));
			g2.setColor(Color.BLACK);
			g2.drawLine(x, y, x + width, y + height);
			g2.drawLine(x + width, y, x, y + height);
			g2.setColor(color);
			g2.setStroke(new BasicStroke(3, BasicStroke.JOIN_ROUND, BasicStroke.CAP_ROUND));
			g2.drawLine(x, y, x + width, y + height);
			g2.drawLine(x + width, y, x, y + height);

		}

		private boolean isUnderMouse(int x, int y) {
			if(Math.abs(x-meX)<width && Math.abs(y-meY)<height )
				return  true;       
			return  false;
		}

		private boolean mouseOverTab(int x, int y) {
			int tabCount = tabbedPane.getTabCount();
			for(int j = 0; j < tabCount; j++)
				if(tabbedPane.getBoundsAt(j).contains(meX, meY)){
					selectedTab = j;
					closeX = tabbedPane.getBoundsAt(j).x + tabbedPane.getBoundsAt(j).width -width-5;
					closeY = tabbedPane.getBoundsAt(j).y +5;                    
					return true;
				}
			return false;
		}

	}

}